Displaylistinterrupt

← Zurück

Von Kveldulfur an Dr. Irata, DrIrata

Hi!

Hier ein kleines Beispiel für den DLI.

Normal hast Du z.B. eine Displaylist für Textmodus 0 die wie folgt aussieht:

StartDspl .BYTE $70, $70, $70 ; Drei leere Zeilen .BYTE $42, ScrMemHi ; GR. 0 -> Speicher definieren .BYTE $02, $02, $02, $02, $02
.BYTE $02, $02, $02, $02, $02
.BYTE $02, $02, $02, $02, $02
.BYTE $02, $02, $02, $02, $02
.BYTE $02, $02, $02 ; 24 Zeilen Gr. 0 insgesamt .BYTE $41, StartDspl

Um den Antic mitzuteilen, wo er einen Interrupt durchführen soll, muss das Bit 7 (+ $80) gesetzt werden. Also z.B. :

StartDspl .BYTE $70, $70, $70 ; Drei leere Zeilen .BYTE $42, ScrMemHi ; GR. 0 -> Speicher definieren .BYTE $02, $02, $02, $02, $02
.BYTE $02, $02, $02, $02, $02
.BYTE $82, $02, $02, $02, $02 ; In Zeile 12 im Textmode einen Interrupt starten .BYTE $02, $02, $02, $02, $02
.BYTE $02, $02, $02 ; 24 Zeilen Gr. 0 insgesamt .BYTE $41, StartDspl

Nun muss der Antic noch wissen, wo Dein Programm steht:

  JSR WaitVSync     ; Auf jedem Fall den Interruptvektor
            ; Im VBI setzen, damit der Computer
            ; nicht abstürzt

  LDA #<DLIStart      ; DLI-Programm in den Adresse VDSLST
  STA VDSLST        ; und VDSLST+1 ablegen.
  LDA #>DLIStart
  STA VDSLST+1

  LDA #NMIEN_DLI | NMIEN_VBI  ; Neben dem VBI soll nun auch der DLI 
  STA NMIEN       ; berücksichtigt werden

Das Programm selbst muss dringend alle Register sichern und den Binärmodus setzen und zum Schluss die Register wiederherstellen:

DLIStart PHA ; Akku auf den Stack sichern TXA PHA ; X Register auf den Stack sichern TYA PHA ; Y Register auf den Stack sichern

      CLD     ; Binärmodus aktivieren

  JSR TitelMusik.MUSPLAY
  JSR xSFX.ENGINE

  PLA     ; Y Register wiederherstellen
  TAY
  PLA     ; X Register wiederherstellen
        TAX
        PLA     ; Akku wiederherstellen
        RTI     ; Return from Interrupt

Die Musik sollte man bevor man den DLI einrichtet schon einmal Initialisieren:

  LDA #$05
  STA TitelMusik.MUMAXDELAY ; Musikgeschwindigkeit
  LDA #$02        ; Anzahl der genutzen Kanäle
  STA TitelMusik.MUKANALCNT+1
  LDA #$01
  STA TitelMusik.MUWAHL   ; Musik-Set wählen
  JSR TitelMusik.MUSINI   ; und Player initialisieren

und kann anschließend jederzeit die Musik so auch ändern.

Antworten

Guten Morgen Janko, vielen Dank für die sehr ausführliche Erklärung! Ich hatte mich ja im Rahmen des Spiels sehr intensiv mit Interrups beschäftigt, da recht schnell klar war, daß ich den VBI brauche. Im weiteren habe ich dann um den VBI zu entlasten mit anderen Interrups experimentiert und dort ein wenig den Tastatur und Break-Interrup kennengelernt... und natürlich auch auf den DLI gestossen. Mir war klar, daß ich den DLI irgendwie gut brauchen könnte und habe versucht diesen in mein Programm mit einzubinden. Irgendwie hat das aber nicht geklappt und ich habe es nicht weiter verfolgt und mir das ganze Thema des DLI für nach BoE terminiert... das war noch vor der ganzen Musik! Irgendwie geht es, aber in der Tat könnte es mit dem DLI viel einfacher und gleichmäßiger sein und sogar Code sparen... ich werde also zunächst noch den Endlosbug rausbauen und den Score mit den Schiffen in Part II fixieren und dann mich gemäß deiner Anleitung um den DLI und der Musik kümmern. Bin mal gespannt, ob die Musik im DLI abgespielt mit dem Scrolling ruckelfrei funktioniert....
Ein Frage vorab dazu: Ich nutze ja Antic 4 und Scrollmodus, in meiner Displaylist steht ja also nicht $2 sondern $24! Muss ich dann die $80 zu den $24 einfach an einer Stelle addieren - also $A4 reinschreiben? Gruß Peter

Antworten

Hallo!

Richtig, der Bit 7 gibt an, dass ein Interrupt durchgeführt werden soll. Bit 7 = %10000000 = $80 Wenn Du also $24 (%00011000) aktuell nutzt und dort Bit 7 setzen willst, musst Du nur $80 addieren = %10011000 = $A4

Denk daran, dass ein Interrupt nicht zusätzliche Zeit holt, sondern lediglich die aktuelle Aufgabe stoppt und eine andere Aufgabe durchführt. Der Interrupt sorgt nur dafür, dass zu bestimmten Ereignissen, bestimmte Aufgaben bearbeitet werden.

VBI = Sorgt dafür, dass genau nach dem Aufbau des Bildes Aufgaben erledigt werden können. DLI = Sorgt dafür, dass genau nach dem Aufbau einer Bildzeile eine Aufgabe erledigt wird. KBI = Sorgt dafür, dass wenn eine Taste gedrückt wurde, diese auch gelesen und in einen Buffer gespeichert wird. BRK = Ist ein Software-Interrupt usw.

Bei Schränker 2 gehe ich nun wie folgt vor:

Im VBI kommen zeitkritische Routinen rein. Bei mir ist das aktuell nur die Stoppuhr. Alles andere wird in einer Hauptschleife ausgeführt, die direkt nach dem VBI (VSync) gestartet wird und darauf wartet. Die Musik wird über den DLI ausgelöst, weil diese so immer außerhalb der kritischen Phase berechnet wird und ebenfalls 100% genau gestartet wird.

Grüße Janko

Antworten

Dass der Interrupt nicht mehr Rechenzeit rausholt ist klar... daher bin ich auch mal gespannt, ob sich das bei mir auswirkt, da das Scrolling schon auch zeitkritisch ist. Vom Aufbau her machst du das sicherlich deutlich besser und klarer als ich. Das muss ich unbedingt beim nächsten Spiel besser berücksichtigen. Daher mal meine Frage dazu:

Die Stoppuhr ist die Zeit für Schränker - also die Zeit, die man für ein Level hat? Der VBI startet ja alle 1/50 Sekunde. Wie machst du denn das Timing VBI / Hauptprogramm? Hast du da so eine Schleife, die immer dann zum Hauptprogramm springt, wenn der VBI einmal durch ist und das der Schleife mitteilt? Was passiert, wenn das Hauptprogramm zu lang wird?? Würde da nicht alles durcheinander kommen??

Antworten

Zwischen dem VBI und den Hauptprogramm gibt es keine besondere Schnittstelle. Die Stoppuhr zählt einfach herunter und bleibt bei 0 stehen.

Wenn ich Zeit durch eine Aktion verliere, ziehe ich die einfach von der Stoppuhr ab. Ist die Stoppuhr bei 0 wird im Hauptprogramm zum Ende gesprungen.

Das Hauptprogramm wartet immer auf den VBI mit dieser Routine:

  .proc WaitVSync

  lda RTCLOK+2

?loop cmp RTCLOK+2 ; will be equal until incremented in VB beq ?loop

  rts

Damit ich weiß, wie lange mein Hauptprogramm benötigt, blende ich immer mal diese Farbbalken ein, die mir zeigen, wann was fertig ist. Ich programmiere so, dass mein Hauptprogramm immer schnell genug fertig ist. Im Extremfall, sollte mein Hauptprogramm länger als 1/50s laufen, würde ggf. alles etwas langsamer oder kurz ruckeln. Aber da ich immer die Rechenzeit im Auge habe, klappt es momentan alles innerhalb der vorgesehene Zeit: Spieler bewegen, Spielfeld bewegen, 28 Geister prüfen/bewegen, 4 Spinnen prüfen/bewegen, Kollisionen prüfen/auswerten. Aber etwas Sorge habe ich schon, dass es noch eng im NTSC-Modus wird.

Janko

Antworten